package bloodfang.gui;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import bloodfang.Attacks;
import bloodfang.Bloodfang;
import bloodfang.CycleCombat2;
import bloodfang.ProcInfo;
import bloodfang.RaidBuff;
import bloodfang.SetBonus;
import bloodfang.Settings;
import bloodfang.StatBlock;
import bloodfang.Stats;
import bloodfang.Weapon;
import bloodfang.WeaponType;

public class GUI2 extends JFrame implements PropertyChangeListener {

	private static final long serialVersionUID = 5753123165374464394L;

	public static void main(String[] args){
		new GUI2();
	}
	
	DBCReader dbcReader = DBCReader.getInstance();
	CharacterReader cr = null;
	
	HashMap<Slot,EquippedItem> slotEquip = new HashMap<Slot,EquippedItem>(); 
	HashMap<Slot,SlotView> slotView = new HashMap<Slot,SlotView>();
	
	JScrollPane selectContainer = null;
	JButton importCharacter = new JButton("Import Char");
	JButton calcBloodfangDPS = new JButton("Calc Bloodfang DPS");
	JTextField outputDPS = new JTextField();
	
	ItemDB itemDB = new ItemDB();
	
	public GUI2(){
		initForm();
		JPanel slotContainer = new JPanel();
		slotContainer.setLayout(new GridLayout(0,2));
		slotContainer.setBorder(BorderFactory.createLineBorder(Color.black));
		for(Slot s : Slot.viewOrder){
			SlotView sv = slotView.get(s);
			slotContainer.add(sv);
		}
		slotContainer.setBounds(0, 0, (int) 2*200, 8*58);
		this.add(slotContainer);
		
		selectContainer = new JScrollPane();
		selectContainer.setBounds(400+5, 0, 400, 8*58);
		selectContainer.setBorder(BorderFactory.createLineBorder(Color.black));
		this.add(selectContainer);
		
		JPanel optionContainer = new JPanel();
		optionContainer.setBounds(0, 8*60, 200, 100);
		optionContainer.setLayout(new GridLayout(0,1));
		optionContainer.add(importCharacter);
		optionContainer.add(calcBloodfangDPS);
		optionContainer.add(outputDPS);
		this.add(optionContainer);
		this.setVisible(true);
	}
	
	private void initForm(){
		this.setSize(900, 700);
		this.setLayout(null);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
			
		importCharacter.addActionListener(new ImportCharacter());
		
		for(Slot slot : Slot.viewOrder){
			if(slot == Slot.shirt || slot == Slot.tabard) continue;
			SlotView sv = new SlotView();
			sv.addUpgradeLevelListener(new UpgradeLevelListener(slot));
			sv.addItemListener(new ShowItemListListener(slot));
			sv.addGemListener(new ShowGemListListener(0, slot));
			sv.addGemListener(new ShowGemListListener(1, slot));
			sv.addGemListener(new ShowGemListListener(2, slot));
			//this.addPropertyChangeListener(sv);
			slotView.put(slot, sv);
		}
		calcBloodfangDPS.setEnabled(false);
		calcBloodfangDPS.addActionListener(new CalcBloodfangDPS());
	}
	
	public void populateSlots(){
		for(Slot slot : slotEquip.keySet()){
			SlotView view = slotView.get(slot);
			EquippedItem ei = slotEquip.get(slot);
			ei.addPropertyChangeListener(view);
			ei.addPropertyChangeListener(this);
			view.setAll(ei);
		}
	}
	
	class ShowItemListListener implements ActionListener{
		
		private final Slot slot;
		
		public ShowItemListListener(Slot slot) {
			this.slot = slot;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			System.out.println(slot);
			
			JPanel container = new JPanel();
			container.setLayout(new GridLayout(0,1));
			for(Item item : itemDB.findAllWithInventorySlot(slot)) {
				JButton itemButton = new JButton(item.getTag() +" "+ item.getName() +" "+ item.getItemLevel());
				itemButton.addActionListener(new ChangeItemListener(slot,item));
				container.add(itemButton);
			}
			
			selectContainer.setViewportView(container);
		}
	}
	
	class ChangeItemListener implements ActionListener {
		
		private final Slot slot;
		private final Item item;
		
		public ChangeItemListener(Slot slot, Item item) {
			this.slot = slot;
			this.item = item;
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {			
			EquippedItem ei = slotEquip.get(this.slot);
			ei.setItemId(this.item.getId());
		}
	}
	
	class ShowGemListListener implements ActionListener{
		
		private final int socketIndex;
		private final Slot slot;
		
		public ShowGemListListener(int socketIndex, Slot slot) {
			this.socketIndex = socketIndex;
			this.slot = slot;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			System.out.println(slot);
			
			JPanel container = new JPanel();
			container.setLayout(new GridLayout(0,1));
			for(Gem gem : itemDB.findAllGemsWithMatchingColor(slot)) {
				JButton itemButton = new JButton(gem.getName() +" "+ gem.getType());
				itemButton.addActionListener(new ChangeGemListener(slot,socketIndex,gem));
				container.add(itemButton);
			}
			
			selectContainer.setViewportView(container);
		}
		
		public int getSocketIndex() {
			return socketIndex;
		}
	}
	
	class ChangeGemListener implements ActionListener {
		
		private final Slot slot;
		private final int socketIndex;
		private final Gem gem;
		
		public ChangeGemListener(Slot slot, int socketIndex, Gem gem) {
			this.slot = slot;
			this.socketIndex = socketIndex;
			this.gem = gem;
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {			
			EquippedItem ei = slotEquip.get(this.slot);
			System.out.println(socketIndex + " " + gem.getId());
			ei.setGem(socketIndex, gem.getId());
		}
	}
	
	class ImportCharacter implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			System.err.println("Import not fully implemented");
			try {
				cr = new CharacterReader("indz","blackmoore","eu");
				slotEquip = cr.getEquippedItems();
				populateSlots();
				calcBloodfangDPS.setEnabled(true);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
	}
	
	class CalcBloodfangDPS implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			calcBloodfang();
		}
	}

	class UpgradeLevelListener implements ActionListener {

		private Slot slot;

		public UpgradeLevelListener(Slot slot){
			this.slot = slot;
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {
			EquippedItem ei = slotEquip.get(this.slot);
			int ulvl = ei.getUpgradeLevel() + 1;
			if(ulvl > 4) ulvl = 0;
			ei.setUpgradeLevel(ulvl);
		}
	}

	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		calcBloodfang();
	}
	
	private void calcBloodfang(){
		Bloodfang bf = new Bloodfang();
		
		StatBlock gearStats = new StatBlock();
		for(Slot slot : slotEquip.keySet()){
			EquippedItem ei = slotEquip.get(slot);
			// item stats
			Item item = (Item) dbcReader.getItemStats(ei);
			gearStats.add(item);
			// gem stats
			for(int gemId : ei.gem_ids) {
				if(gemId != 0){
					Gem gem = ItemDB.getGem(gemId);
					gearStats.add(gem);
				}
			}
			// enchant stats
			gearStats.add(dbcReader.getEnchantStats(ei));
		}
		System.out.println(gearStats);
		
		Item _mh = (Item) dbcReader.getItemStats(slotEquip.get(Slot.mainHand));
		Item _oh = (Item) dbcReader.getItemStats(slotEquip.get(Slot.offHand));
		Weapon mh = new Weapon(_mh.getDps(),_mh.getSpeed(),WeaponType.MACE);
		Weapon oh = new Weapon(_oh.getDps(),_oh.getSpeed(),WeaponType.DAGGER);
		
		String tal = "221102";
		
		EnumSet<SetBonus> setB = EnumSet.of(SetBonus.T15_2PC,SetBonus.T15_4PC);
		setB = EnumSet.noneOf(SetBonus.class);
		
		HashSet<ProcInfo> procs = new HashSet<ProcInfo>();
		procs.add(new ProcInfo("heroic_war_assurance_of_consequence",2));
		procs.add(new ProcInfo("heroic_war_haromms_talisman",2));
		procs.add(new ProcInfo("capacitive_primal_diamond"));
		procs.add(new ProcInfo("fury_of_xuen"));
		procs.add(new ProcInfo("mh_dancing_steel"));
		procs.add(new ProcInfo("oh_dancing_steel"));
		
		Settings settings = new Settings();
		// Stats(Settings _settings, StatBlock _gearStats, Race _race, Weapon _mh, Weapon _oh,String _talents, EnumSet<RaidBuff> _raidBuffs, EnumSet<SetBonus> _setBonuses, HashSet<ProcInfo> procs) {
		// System.out.println(cr.getRace());
		bf.stats = new Stats(settings, gearStats, cr.getRace(), mh, oh, tal, new HashSet<String>(), EnumSet.allOf(RaidBuff.class), setB, procs);
		bf.attacks = new Attacks(bf.stats);
		
		bf.cycle = new CycleCombat2(bf.stats,bf.attacks);
		double dps = bf.cycle.get_dps();
		System.out.println("DPS: " + dps);
		outputDPS.setText(Double.toString(dps));
	}
}
